
export default class Model {
    public static model:{
        account?:{
            nickname?:string,
            username?:string
        },
        room?:{
            status:number,
            playerCount:number,
            player?:Array<{
                uid:string, 
                nickname:string, 
                prepare:boolean,
                card?:Array<[number,number]>, 
                goneCard?:Array<[number,number]>, 
                winCard?:Array<[[number,number],[number,number],[number,number]]>
            }>,
            card?:Array<[number,number]>,
            speaker?:number,
            speakerTime?:number
        }
    } = {};
    private static listenerTree0 = {children:{}, listener:{}};
    private static listenerTree1 = {children:{}, listener:{}};
    private static called1 = {};
    private static called2 = {};
    private static calledIdKeys = {};
    /**
     * 更新数据
     * @param data 后端发来的model格式
     */
    public static update (data) {
        // 用于记录所有触发过的事件key
        Model.called1 = {};
        Model.called2 = {};
        // 记录所有触发过的cb
        Model.calledIdKeys = {};
        // 修改model的值
        for (var i = 0; i < data.length; i++) {
            Model.setValue(data[i]);
        }
    
        // 发送事件
        for (var order = 0; order < 2; order++) {
            for (var j = 0; j < data.length; j++) {
                Model.dispatchEvent(data[j].key, order);            
            }
        }
    };
    
    /**
    设置值
    {key="model.tank.info.t1101", value={}}
    当没有value时，理解为删除这个key
    */
    private static setValue (action){
        var keys = action.key.split(".");
        var curData = Model;
        for (var i = 0; i < keys.length; i++) {
            var trueKey = keys[i];
            if (keys[i].indexOf("[") === 0 && keys[i].indexOf("]") === keys[i].length - 1) {
                trueKey = parseInt(keys[i].substring(1,keys[i].length - 1));
            }
            if (i < keys.length-1) {
                curData = curData[trueKey];
            } else {
                curData[trueKey] = action.value;
            }
        }
    };
    
    /**
    添加监听器
    @param key 监听的key
    @param cb  回调
    @param order 优先级，只支持0和1，ui请用1，逻辑model请用0
    @param idKey 用于标识一个唯一的回调，idKey相同的，在同一次数据返回里，不会被调用多次，
                字符串类型，对于model来说，推荐设置为类似这样的："OfficerModel:refreshData"
    @return    监听句柄
    */
    public static addListener (key, cb, order, idKey?){
        var keys = key.split(".");
        var curData = this["listenerTree" + order];
        for (var i = 0; i < keys.length; i++) {
            if (!curData.children[keys[i]]) {
                curData.children[keys[i]] = {children:{}, listener:{}, listenerHand:0};
            }
            curData = curData.children[keys[i]];
        }
        // 句柄+1,存下cb
        curData.listenerHand ++;
        curData.listener[curData.listenerHand.toString()] = {cb:cb,idKey:idKey};

        return order + "$" + key + "$" + curData.listenerHand;
    };
    /**
    移除监听器
    @param hand 监听句柄
    */
    public static removeListener (hand) {
        // print("Model:removeListener")
        var spl = hand.split("$");
        var order = spl[0];
        var key = spl[1];
        var listenerHand = spl[2];
        // print("key,listenerHand", key, listenerHand)

        var keys = key.split(".");
        var curData = this["listenerTree" + order];
        for (var i = 0; i < keys.length; i++) {
            curData = curData.children[keys[i]];
            if (!curData){
                console.error("Model:removeListener cannot find this hand", hand);
            }
        }
        delete curData.listener[listenerHand];
    };

    private static dispatchEvent (key, order) {
        var keys = key.split(".");
        var curData = this["listenerTree" + order];
        var callKey = "";
        for (var i = 0; i < keys.length; i++) {

            curData = curData.children[keys[i]];
            if (!curData) {
                break;
            }
            callKey = callKey + keys[i] + ".";
            // 如果还没有通知过该key,则通知，并记录已经通知过了
            if (!this["called" + order][callKey]) {
                // 必须先取出所有key再进行遍历，不然会有遍历删除的问题
                var listenerKLeys = Object.keys(curData.listener);
                for (var j = 0; j < keys.length; j++) {
                    if (curData.listener[listenerKLeys[j]]) {
                        var idKey = curData.listener[listenerKLeys[j]].idKey;
                        if ((!idKey) || (!this.calledIdKeys[idKey])) {
                            curData.listener[listenerKLeys[j]].cb();
                            if (idKey) {
                                this.calledIdKeys[idKey] = true;
                            }
                        }
                    }
                }
                this["called" + order][callKey] = true;
            }
        }
        if (curData) {
            this.dispatchEventAll(curData, callKey, order);
        }
    };
    // 递归调用，用于通知某个声源的所有子声源
    private static dispatchEventAll = function (curData, callKey, order) {
        if (curData) {
            // 如果还没有通知过该key,则通知，并记录已经通知过了
            if (!this["called" + order][callKey]) {
                // 必须先取出所有key再进行遍历，不然会有遍历删除的问题
                var keys = Object.keys(curData.listener);
                for (var i = 0; i < keys.length; i++) {
                    if (curData.listener[keys[i]]) {
                        var idKey = curData.listener[keys[i]].idKey;
                        if ((!idKey) || (! this.calledIdKeys[idKey])) {

                            curData.listener[keys[i]].cb();
                            if (idKey) {
                                this.calledIdKeys[idKey] = true;
                            }
                        }
                    }
                }
                this["called" + order][callKey] = true;
            }
            var keys = Object.keys(curData.children);
            for (var i = 0; i < keys.length; i++) {
                this.dispatchEventAll(curData.children[keys[i]], callKey + keys[i] + ".", order);
            }
        }
    };
    /** 清空 */
    public static clear = function () {
        Model.model = {};        
        Model.listenerTree0 = {children:{}, listener:{}};
        Model.listenerTree1 = {children:{}, listener:{}};
    };

}
